/*   Copyright (C) 2011 Wolfgang Hankeln, Norma J. Wendel
 *
 *   This file is part of CDinFusion.
 *
 *   CDinFusion is free software: you can redistribute it and/or
 *   modify it under the terms of the GNU Lesser General Public 
 *   License in version 3 (LGPL3) as published by the Free Software
 *   Foundation version 3 of the License.
 *
 *   CDinFusion is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *   Lesser General Public License for more details.
 *
 *   You should have received a copy of the Lesser General Public
 *   License along with CDinFusion; see the file COPYING. If not,
 *   write to the Free Software Foundation, 59 Temple Place - Suite 330,
 *   Boston, MA 02111-1307, USA or see <http://www.gnu.org/licenses/>.
 *   
 *   If you have any questions, send an email to: megx@mpi-bremen.de.
 */
package org.cdinfusion.web.controller;

import java.io.File;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import org.cdinfusion.data.CDElement;
import org.cdinfusion.data.CDElementHelper;
import org.cdinfusion.filehandling.CSVHandler;
import org.cdinfusion.filehandling.FastaReader;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.webflow.action.AbstractAction;
import org.springframework.webflow.core.collection.ParameterMap;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.RequestContext;

import de.mpi_bremen.mgg.FastaValidator.FastaValidator;

public class FileUploadActionController extends AbstractAction {

	protected Event doExecute(RequestContext context) throws Exception {
		System.out.println("##### FileUploadActionController #####");

		ParameterMap pam = context.getRequestParameters();
		String sessionID = pam.asAttributeMap().getRequiredString("sessionID");
		MultipartFile file = context.getRequestParameters()
				.getRequiredMultipartFile("file");
		String ofname = file.getOriginalFilename();

		int dot = ofname.indexOf(".");
		String ofn_extension = ofname.substring(dot + 1);
		String message = "";
		Timestamp tstamp = new Timestamp(System.currentTimeMillis());
		System.out.println("first lines FUAC tstamp: " + tstamp + " "
				+ tstamp.getTime());

		if (file.getSize() > 0) {
			if (isFastaFile(ofn_extension)) {
				try {
					message = handleFastaFile(context, sessionID, file);
				} catch (Exception e) {
					message = e.getMessage();
					System.out.println("ERROR FUAC! " + message);
					context.getFlashScope().put("message", message);
					context.getFlashScope().put("try", "Try again please!");

					return error(e);
				}
			} else if (ofn_extension.contains("csv")) {
				try {
					message = handleCSVFile(context, pam, sessionID, file);
				} catch (final Exception e) {
					message = "ERROR in CSVHandler: " + e.getMessage();
					System.out.println("ERROR FUAC! " + message);
					context.getFlashScope().put("message", message);
					context.getFlashScope().put("try", "Try again please!");
					return error(e);

				}
			} else {
				message = "The extention of your file is incorrect.\n"
						+ "If you try to upload a sequence file,\n"
						+ "use the extension fasta, fna, ffn, faa, seqa.\n"
						+ "Use csv for the CD file.\n";
				context.getFlashScope().put("message", message);
			}

			if (message.equals("success")) {
				return success();
			} else {
				return error();
			}
		} else {
			return error();
		}
	}

	private String handleCSVFile(RequestContext context, ParameterMap pam,
			String sessionID, MultipartFile file) throws IOException {

		String message = "success";
		context.getFlashScope().put("destination", "csv");
		Timestamp tstamp;

		String folder = String.format("%s/webapps/CDinFusion/data/",
				System.getenv("CATALINA_HOME"));
		new File(folder).mkdir();

		final File destfile = new File(folder, sessionID + ".csv");
		file.transferTo(destfile);
		final CSVHandler csvh = new CSVHandler();

		tstamp = new Timestamp(System.currentTimeMillis());
		System.out.println("before readCSVfromFile tstamp: " + tstamp + " "
				+ tstamp.getTime());

		final List<CDElement> cdeLIST = csvh.readCSVfromFile(
				destfile.getAbsolutePath(), sessionID);

		tstamp = new Timestamp(System.currentTimeMillis());
		System.out.println("after readCSVfromFile tstamp: " + tstamp + " "
				+ tstamp.getTime());

		context.getFlowScope().put("cdeLIST", cdeLIST);

		// from upload jsp a String is retrieved that contains
		// already used sequences
		List<String> usedSequenceIDs = new ArrayList<String>();
		String uSIDs = "";
		// initial == true => first time, no sequences used so far
		// initial == false => used sequences are existing
		// if clause prevents that it is tried to retrieve used
		// sequences that are no existing
		if (pam.asAttributeMap().getRequiredString("initial").contains("false")) {
			uSIDs = pam.asAttributeMap().getRequiredString("uSIDs");

			String[] split = uSIDs.split(",");
			for (int i = 0; i < split.length; i++) {
				usedSequenceIDs.add(split[i].trim());
			}
		}

		// used sequences + now newly used sequences
		@SuppressWarnings("unchecked")
		final List<String> currentlySelectedSIDs = CDElementHelper
				.getUsedSequenceIDs((List<String>) context.getExternalContext()
						.getSessionMap().get("allSequenceIDs"), cdeLIST.get(0));
		usedSequenceIDs.addAll(currentlySelectedSIDs);
		context.getFlowScope().put("usedSequenceIDs", usedSequenceIDs);
		context.getFlowScope().put("currentlySelectedSIDs",
				currentlySelectedSIDs);
		System.out
				.println("successful: cdeList, currentlySelectedSIDs, usedSequenceIDs now in FlowScope");

		context.getFlashScope().put("message", message);

		return message;
	}

	private String handleFastaFile(RequestContext context, String sessionID,
			MultipartFile file) throws IllegalStateException, IOException {

		// initialize
		String message = "success";
		Timestamp tstamp = new Timestamp(System.currentTimeMillis());
		List<String> allSequenceIDs = new ArrayList<String>();
		int numberOfSequencesUploaded = 0;

		System.out.println("Before fasta validation: " + tstamp + " "
				+ tstamp.getTime());
		String folder = String.format("%s/webapps/CDinFusion/data/",
				System.getenv("CATALINA_HOME"));
		new File(folder).mkdir();

		File destfile = new File(folder, "raw_" + sessionID + ".fasta");
		file.transferTo(destfile);

		String fasta_message = "fasta upload successful!";
		try {
			final FastaReader fr = new FastaReader();
			final FastaValidator fv = new FastaValidator(fr);
			System.out.println("FV: " + folder + destfile.getName());
			// FASTA validation
			fv.validate(destfile.getAbsolutePath());
			allSequenceIDs = fr.returnPlainSeqIDs();
			numberOfSequencesUploaded = fr.getNumberOfSequences();

			System.out.println("After fasta validation: " + tstamp + " "
					+ tstamp.getTime());

		} catch (Exception e) {
			System.out.println("ERROR: " + e.getMessage());
			fasta_message = "fasta upload failed!";
			message = e.getMessage();
		}
		context.getFlashScope().put("fasta_message", fasta_message);
		tstamp = new Timestamp(System.currentTimeMillis());
		System.out.println("after fh.returnSeqIDs tstamp: " + tstamp + " "
				+ tstamp.getTime());

		final String destination;
		if (allSequenceIDs.size() > 1) {
			destination = "many";
		} else {
			destination = "one";
		}
		context.getFlashScope().put("destination", destination);

		context.getExternalContext().getSessionMap()
				.put("numberOfSequencesUploaded", numberOfSequencesUploaded);

		context.getFlowScope().put("allSequenceIDs", allSequenceIDs);
		context.getFlashScope().put("message", message);

		return message;
	}

	private static boolean isFastaFile(String ofn_extension) {
		return ofn_extension.contains("fasta")
				|| ofn_extension.contains("fna")
				|| ofn_extension.contains("ffn")
				|| ofn_extension.contains("faa")
				|| ofn_extension.contains("frn")
				|| ofn_extension.contains("fas")
				|| ofn_extension.contains("seqa");
	}
}